﻿#pragma once

#include <atomic>
#include <chrono>
#include <functional>
#include <iostream>
#include <map>
#include <thread>

namespace xi
{

// 高精度计时器
typedef std::chrono::high_resolution_clock __clock;
typedef std::chrono::milliseconds __milliseconds;
typedef std::chrono::microseconds __microseconds;
typedef std::chrono::seconds __seconds;

#ifndef NDEBUG

#define RUNTIME_COUNT 1000
#define RUNTIME_START __clock::time_point __RUNTIMER_CLOCK_START = __clock::now();

#define RUNTIME_END(NAME)                                                                                              \
    __clock::time_point __RUNTIMER_CLOCK_END = __clock::now();                                                         \
    {                                                                                                                  \
        static int count = 0;                                                                                          \
        static long long duration = 0;                                                                                 \
        duration += std::chrono::duration_cast<__microseconds>(__RUNTIMER_CLOCK_END - __RUNTIMER_CLOCK_START).count(); \
        if (++count == RUNTIME_COUNT)                                                                                  \
        {                                                                                                              \
            std::cout << NAME << " average time: " << float(duration) / count << "us\n";                               \
            duration = 0;                                                                                              \
            count = 0;                                                                                                 \
        }                                                                                                              \
    }

#else

#define RUNTIME_COUNT
#define RUNTIME_START
#define RUNTIME_END(NAME)

#endif

#define TIMER_START(NAME) __clock::time_point __TIMER##NAME##_START = __clock::now();
#define TIMER_END(NAME)                                                                                                \
    __clock::time_point __TIMER##NAME##_END = __clock::now();                                                          \
    {                                                                                                                  \
        auto d = std::chrono::duration_cast<__microseconds>(__TIMER##NAME##_END - __TIMER##NAME##_START).count();      \
        std::cout << "Timer " << #NAME << ": " << d << "us\n";                                                         \
    }

namespace utils
{

class Timer
{
    friend class TimerManager;

  public:
    /**
     * @brief 设置重复次数
     *
     * @param[in] repeat
     */
    explicit Timer(int repeat = -1) : m_period(0), m_repeat(repeat)
    {
        m_time = now();
    }

    /**
     * @brief 装载回调函数
     *
     * @tparam F
     * @tparam Args
     * @param[in] period
     * @param[in] func
     * @param[in] args
     */
    template <typename F, typename... Args> void callback(int period, F &&func, Args &&...args)
    {
        m_period = period;
        m_func = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
    }

    /**
     * @brief 启用定时器
     *
     * @return true
     * @return false
     */
    bool on_timer()
    {
        if (!m_func || m_repeat == 0)
            return false;

        // 考虑执行时间
        m_func();
        m_time += m_period;
        if (m_repeat > 0)
            m_repeat--;
        return true;
    }

  private:
    /**
     * @brief 获得当前时间
     *
     * @return int64_t
     */
    static int64_t now()
    {
        return std::chrono::duration_cast<std::chrono::milliseconds>(
                   std::chrono::system_clock::now().time_since_epoch())
            .count();
    }

  private:
    std::function<void()> m_func;
    int64_t m_time; // 触发时间
    int m_period;   // 触发间隔 ms
    int m_repeat;   // 重复次数 -1 表示无限循环
};

class TimerManager
{
  public:
    explicit TimerManager() = default;

    /**
     * @brief 注册定时器
     *
     * @tparam F
     * @tparam Args
     * @param[in] period
     * @param[in] func
     * @param[in] args
     */
    template <typename F, typename... Args> void schedule(int period, F &&func, Args &&...args)
    {
        Timer timer;
        timer.callback(period, std::forward<F>(func), std::forward<Args>(args)...);
        m_timers.insert(std::make_pair(timer.m_time, timer));
    }

    /**
     * @brief 注册定时器
     *
     * @tparam F
     * @tparam Args
     * @param[in] period
     * @param[in] repeat
     * @param[in] func
     * @param[in] args
     */
    template <typename F, typename... Args> void schedule(int period, int repeat, F &&func, Args &&...args)
    {
        Timer timer(repeat);
        timer.callback(period, std::forward<F>(func), std::forward<Args>(args)...);
        m_timers.insert(std::make_pair(timer.m_time, timer));
    }

    /**
     * @brief 更新定时器
     *
     * @return true
     * @return false
     */
    bool update()
    {
        if (m_timers.empty())
            return false;

        int64_t now = Timer::now();
        for (auto it = m_timers.begin(); it != m_timers.end();)
        {
            // 如果第一个计时器还没到时间，则后面的一定还没到时间，直接返回
            if (it->first > now)
                return false;
            it->second.on_timer();

            // 移除当前迭代器，自动获得下一个迭代器
            auto t = it->second;
            it = m_timers.erase(it);

            // 如果还没执行完，则重新插入
            if (t.m_repeat != 0)
            {
                auto newIt = m_timers.insert(std::make_pair(t.m_time, t));

                // 如果新插入的位置比当前位置靠前，则更新当前位置
                if (it == m_timers.end() || newIt->first < it->first)
                    it = newIt;
            }
        }

        return true;
    }

  private:
    // 使用定时器时间戳排序
    std::multimap<int64_t, Timer> m_timers;
};

} // namespace utils

} // namespace xi
